package org.jivesoftware.openfire.redischat;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;



import org.jivesoftware.database.DbConnectionManager;
import org.jivesoftware.openfire.muc.MUCRoom;
import org.jivesoftware.util.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class RedisMUCPersistenceManager {

	private static final Logger Log = LoggerFactory.getLogger(RedisMUCPersistenceManager.class);

    private static final String GET_RESERVED_NAME =
        "SELECT nickname FROM tMucMember WHERE roomID=? AND jid=?";

    private static final String UPDATE_SUBJECT =
        "UPDATE tMucRoom SET subject=? WHERE roomID=?";

    private static final String UPDATE_EMPTYDATE =
        "UPDATE tMucRoom SET emptyDate=? WHERE roomID=?";
    
    private static ConcurrentHashMap<String,RedisMUCServiceProperties> propertyMaps = new ConcurrentHashMap<String,RedisMUCServiceProperties>();

    public static String getReservedNickname(MUCRoom room, String bareJID) {
        Connection con = null;
        PreparedStatement pstmt = null;
        ResultSet rs = null;
        String answer = null;
        try {
            con = DbConnectionManager.getConnection();
            pstmt = con.prepareStatement(GET_RESERVED_NAME);
            pstmt.setLong(1, room.getID());
            pstmt.setString(2, bareJID);
            rs = pstmt.executeQuery();
            if (rs.next()) {
                answer = rs.getString(1);
            }
        }
        catch (SQLException sqle) {
            Log.error(sqle.getMessage(), sqle);
        }
        finally {
            DbConnectionManager.closeConnection(rs, pstmt, con);
        }
        return answer;
    }
    

    public static void updateRoomSubject(MUCRoom room) {
        if (!room.isPersistent() || !room.wasSavedToDB()) {
            return;
        }

        Connection con = null;
        PreparedStatement pstmt = null;
        try {
            con = DbConnectionManager.getConnection();
            pstmt = con.prepareStatement(UPDATE_SUBJECT);
            pstmt.setString(1, room.getSubject());
            pstmt.setLong(2, room.getID());
            pstmt.executeUpdate();
        }
        catch (SQLException sqle) {
            Log.error(sqle.getMessage(), sqle);
        }
        finally {
            DbConnectionManager.closeConnection(pstmt, con);
        }
    }


    public static void updateRoomEmptyDate(MUCRoom room) {
        if (!room.isPersistent() || !room.wasSavedToDB()) {
            return;
        }

        Connection con = null;
        PreparedStatement pstmt = null;
        try {
            con = DbConnectionManager.getConnection();
            pstmt = con.prepareStatement(UPDATE_EMPTYDATE);
            Date emptyDate = room.getEmptyDate();
            if (emptyDate == null) {
                pstmt.setString(1, null);
            }
            else {
                pstmt.setString(1, StringUtils.dateToMillis(emptyDate));
            }
            pstmt.setLong(2, room.getID());
            pstmt.executeUpdate();
        }
        catch (SQLException sqle) {
            Log.error(sqle.getMessage(), sqle);
        }
        finally {
            DbConnectionManager.closeConnection(pstmt, con);
        }
    }


    public static String getProperty(String subdomain, String name) {    	
    	final RedisMUCServiceProperties newProps = new RedisMUCServiceProperties(subdomain);
    	final RedisMUCServiceProperties oldProps = propertyMaps.putIfAbsent(subdomain, newProps);
    	if (oldProps != null) {
    		return oldProps.get(name);
    	} else {
    		return newProps.get(name);
    	}
    }

    public static String getProperty(String subdomain, String name, String defaultValue) {
    	final String value = getProperty(subdomain, name);
    	if (value != null) {
    		return value;
    	} else {
    		return defaultValue;
    	}
    }

    public static int getIntProperty(String subdomain, String name, int defaultValue) {
        String value = getProperty(subdomain, name);
        if (value != null) {
            try {
                return Integer.parseInt(value);
            }
            catch (NumberFormatException nfe) {
            }
        }
        return defaultValue;
    }

    public static long getLongProperty(String subdomain, String name, long defaultValue) {
        String value = getProperty(subdomain, name);
        if (value != null) {
            try {
                return Long.parseLong(value);
            }
            catch (NumberFormatException nfe) {
            }
        }
        return defaultValue;
    }

    public static boolean getBooleanProperty(String subdomain, String name) {
        return Boolean.valueOf(getProperty(subdomain, name));
    }

    public static boolean getBooleanProperty(String subdomain, String name, boolean defaultValue) {
        String value = getProperty(subdomain, name);
        if (value != null) {
            return Boolean.valueOf(value);
        }
        else {
            return defaultValue;
        }
    }

    public static List<String> getPropertyNames(String subdomain, String parent) {
    	RedisMUCServiceProperties properties = new RedisMUCServiceProperties(subdomain);
    	final RedisMUCServiceProperties oldProps = propertyMaps.putIfAbsent(subdomain, properties);
    	if (oldProps != null) {
    		properties = oldProps;
    	} 
        return new ArrayList<String>(properties.getChildrenNames(parent));
    }

    public static List<String> getProperties(String subdomain, String parent) {
    	RedisMUCServiceProperties properties = new RedisMUCServiceProperties(subdomain);
    	final RedisMUCServiceProperties oldProps = propertyMaps.putIfAbsent(subdomain, properties);
    	if (oldProps != null) {
    		properties = oldProps;
    	} 

        Collection<String> propertyNames = properties.getChildrenNames(parent);
        List<String> values = new ArrayList<String>();
        for (String propertyName : propertyNames) {
            String value = getProperty(subdomain, propertyName);
            if (value != null) {
                values.add(value);
            }
        }

        return values;
    }

    public static List<String> getPropertyNames(String subdomain) {
    	RedisMUCServiceProperties properties = new RedisMUCServiceProperties(subdomain);
    	final RedisMUCServiceProperties oldProps = propertyMaps.putIfAbsent(subdomain, properties);
    	if (oldProps != null) {
    		properties = oldProps;
    	} 
        return new ArrayList<String>(properties.getPropertyNames());
    }

    public static void setProperty(String subdomain, String name, String value) {
        RedisMUCServiceProperties properties = propertyMaps.get(subdomain);
        if (properties == null) {
            properties = new RedisMUCServiceProperties(subdomain);
        }
        properties.put(name, value);
        propertyMaps.put(subdomain, properties);
    }

    public static void setLocalProperty(String subdomain, String name, String value) {
        RedisMUCServiceProperties properties = propertyMaps.get(subdomain);
        if (properties == null) {
            properties = new RedisMUCServiceProperties(subdomain);
        }
        properties.localPut(name, value);
        propertyMaps.put(subdomain, properties);
    }

    public static void setProperties(String subdomain, Map<String, String> propertyMap) {
        RedisMUCServiceProperties properties = propertyMaps.get(subdomain);
        if (properties == null) {
            properties = new RedisMUCServiceProperties(subdomain);
        }
        properties.putAll(propertyMap);
        propertyMaps.put(subdomain, properties);
    }

    public static void deleteProperty(String subdomain, String name) {
        RedisMUCServiceProperties properties = propertyMaps.get(subdomain);
        if (properties == null) {
            properties = new RedisMUCServiceProperties(subdomain);
        }
        properties.remove(name);
        propertyMaps.put(subdomain, properties);
    }

    public static void deleteLocalProperty(String subdomain, String name) {
        RedisMUCServiceProperties properties = propertyMaps.get(subdomain);
        if (properties == null) {
            properties = new RedisMUCServiceProperties(subdomain);
        }
        properties.localRemove(name);
        propertyMaps.put(subdomain, properties);
    }

    public static void refreshProperties(String subdomain) {
        propertyMaps.replace(subdomain, new RedisMUCServiceProperties(subdomain));
    }
    
}